//-WinterFramework ? WinterFeather
using System;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.UI;
using System.IO;

#if UNITY_EDITOR
using UnityEditor;
#endif


public class SoundManager : SingleMono<SoundManager>
{
    AssetBundle bundle;
    public AssetBundle Bundle => bundle;
    Dictionary<SoundStyle, SoundTrack> soundTrack;
    public Dictionary<SoundStyle, SoundTrack> SoundTrack => soundTrack;
    public const bool IS_USE_RESOURCE = false;
    public bool isEditorMode = false;
    public bool isDebug = false;
    public readonly string resourcePath = "UIPanel/";
    public readonly string assetPath = "Assets/WResources/Sound/";
    public void SetBundle(AssetBundle bundle)
    {
        this.bundle = bundle;
    }
    public void Init()
    {
        var enumValues = Enum.GetValues(typeof(SoundStyle));

        soundTrack = new Dictionary<SoundStyle, SoundTrack>();

        foreach (var item in enumValues)
        {
            SoundTrack st = new SoundTrack();
            SoundStyle ss = (SoundStyle)Enum.Parse(typeof(SoundStyle), item.ToString());
            st.Init(ss, false);
            soundTrack.Add(ss, st);
        }
        soundTrack[SoundStyle.backGround].isSingle = true;
    }
    public void PauseSwich(SoundStyle soundStyle)
    {
        soundTrack[soundStyle].PauseSwich();
    }
    public void Pause(SoundStyle soundStyle)
    {
        soundTrack[soundStyle].Pause();
    }
    public void Play(SoundStyle soundStyle)
    {
        soundTrack[soundStyle].Play();
    }
    public void SetVolum( SoundStyle soundStyle,float volum)
    {
        soundTrack[soundStyle].SetVolum(volum);
    }
    public void SetMute(SoundStyle soundStyle, bool isMute)
    {
        soundTrack[soundStyle].SetMute(isMute);
    }
    public void SetLoop(SoundStyle soundStyle, bool isLoop)
    {
        soundTrack[soundStyle].SetLoop(isLoop);
    }
    public float GetVolum(SoundStyle soundStyle)
    {
        return soundTrack[soundStyle].Volum;
    }
    public bool GetMute(SoundStyle soundStyle)
    {
        return soundTrack[soundStyle].IsMute;
    }
    public bool GetLoop(SoundStyle soundStyle)
    {
        return soundTrack[soundStyle].IsLoop;
    }
    public SoundPlayerNode Play(string name, SoundStyle soundStyle = SoundStyle.effect, float baseVolume = 1, bool isUseResource = false)
    {
        return soundTrack[soundStyle].AddNode(name, null,baseVolume, isUseResource);
    }
    public SoundPlayerNode Play3D(string name, Vector3 pos, SoundStyle soundStyle = SoundStyle.effect, float baseVolume = 1, bool isUseResource = false)
    {
        return soundTrack[soundStyle].AddNode(name, pos, baseVolume, isUseResource);
    }
    public class Debug:DebugHelper
    {
        public static void LogError(object s)
        {
            if(Instance.isDebug)
            UnityEngine.Debug.LogError(s);
        }
        public static void Log(object s)
        {
            if(Instance.isDebug)
            UnityEngine.Debug.Log(s);
        }
    }
}



public enum SoundStyle
{
    backGround, effect
}

public class SoundTrack
{
    public SoundStyle soundStyle;
    LinkedList<SoundPlayerNode> nodes;
    public LinkedList<SoundPlayerNode> Nodes => nodes;
    public bool isSingle;

    bool isLoop;
    public bool IsLoop => isLoop;


    bool isPause;
    public bool IsPause => isPause;
    float volum;
    public float Volum => volum;
    bool isMute;
    public bool IsMute => isMute;


    public void Init(SoundStyle soundStyle, bool isloop)
    {
        this.soundStyle = soundStyle;
        this.isLoop = isloop;
        nodes = new LinkedList<SoundPlayerNode>();
        {
            volum = 1;
        }
    }

    public void SetLoop(bool loop)
    {
        this.isLoop = loop;
    }

    public void SetVolum(float volum)
    {
        this.volum = volum;
        foreach (var item in nodes)
        {
            item.SetVolum(volum); //.audioSource.volume = volum;
        }
    }

    public void SetMute(bool isMute)
    {
        this.isMute = isMute;
        foreach (var item in nodes)
        {
            item.audioSource.mute = isMute;
        }
    }

    public void PauseSwich()
    {
        isPause = !isPause;
        if (isPause)
        {
            Pause();
        }
        else
        {
            Play();
        }
    }

    public void Pause()
    {
        foreach (var item in nodes)
        {
            item.audioSource.Pause();
        }
    }

    public void Play()
    {
        foreach (var item in nodes)
        {
            item.audioSource.Play();
        }
    }

    public SoundPlayerNode AddNode(string soundName, Vector3? pos = null, float baseVolume = 1, bool isUseResource = false)
    {
        if (isSingle && nodes.Count > 0)
        {
            if (nodes.First != null)
                nodes.First.Value.Destroy();
            else
                nodes.RemoveFirst();
        }
        //nodes.First.Value.Destroy();

        SoundPlayerNode node = ObjectPoolManager.Instance.DePool<SoundPlayerNode>("SoundPlayer", SoundManager.IS_USE_RESOURCE, "Common");
        if (pos != null)
        {
            node.transform.position = pos.Value;
            //node.audioSource.
        }
        node.transform.SetParent(SoundManager.Instance.transform);
        node.Init(soundName, this,baseVolume, isUseResource);

        var linkNOde = new LinkedListNode<SoundPlayerNode>(node);
        nodes.AddLast(linkNOde);
        return node;
    }

    public void RemoveNode(SoundPlayerNode node)
    {
        nodes.Remove(node);
    }
}

public class SoundPlayerNode : BasePoolElement
{
    public AudioSource audioSource;
    SoundTrack track;
    float playerTime;
    float baseVolume;
    string soundName;

    public Action<SoundPlayerNode> onPlayEnd;
    public Action<SoundPlayerNode> onPlaying;
    bool isUseResource = false;
    public void Init(string soundName, SoundTrack track, float baseVolume = 1, bool isUseResource=false)
    {
        if (audioSource == null) audioSource = gameObject.AddComponent<AudioSource>();

        this.track = track;
        this.baseVolume = baseVolume;
        playerTime = 0;
        this.isUseResource = isUseResource;
        this.soundName = soundName;
        if (isUseResource)
        {
            audioSource.clip = Resources.Load<AudioClip>($"Sound/{soundName}");
        }
        else
        {
            if (SoundManager.Instance.isEditorMode && Application.isEditor)
            {
#if UNITY_EDITOR
                audioSource.clip = AssetDatabase.LoadAssetAtPath<AudioClip>(Path.Combine(SoundManager.Instance.assetPath) + soundName);
                if (audioSource.clip == null)
                {
                    UnityEngine.Debug.LogError(Path.Combine(SoundManager.Instance.assetPath) + soundName+" is null");
                }
#endif
            }
            else
            {
                audioSource.clip = SoundManager.Instance.Bundle.LoadAsset<AudioClip>(soundName);
            }
        }

        SetVolum(track.Volum);
        SetMute(track.IsMute);
        SetLoop(track.IsLoop);

        if (track.IsPause)
        {
            audioSource.Pause();
        }
        else
        {
            audioSource.Play();
        }

        onPlayEnd = End;
    }
    private void FixedUpdate()
    {
        if (audioSource.isPlaying)
        {
            playerTime += Time.fixedDeltaTime;
            onPlaying?.Invoke(this);
        }
        if (!audioSource.isPlaying && !track.IsPause)
        {
            onPlayEnd?.Invoke(this);
        }
    }

    void End(SoundPlayerNode node)
    {
        if (node.track.IsLoop)
        {
            node.Init(soundName, node.track, baseVolume, isUseResource);
        }
        else
        {
            node.Destroy();
        }
    }

    public void Destroy()
    {
        track.RemoveNode(this);
        if (audioSource!= null)
        audioSource.Stop();
        ObjectPoolManager.Instance.EnPool(this);
    }

    internal void SetVolum(float volum)
    {
        audioSource.volume = volum * baseVolume;
    }
    internal void SetMute(bool isMute)
    {
        audioSource.mute = isMute;
    }
    internal void SetLoop(bool isLoop)
    {
        audioSource.loop = isLoop;
    }

    float[] samples = new float[20];

}

